﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using Common.Utilities;
using Common.Utilities.Dispatcher;

namespace Workflows.Components.TextMining.NamedEntities
{
    /// <summary>
    /// 
    /// </summary>
    [Serializable]
    public class OrganizationEncodingInstruction:InstructionBase
    {
        #region props
        private string _ConnStr;
        /// <summary></summary>
        public string ConnStr
        {
            get
            {
                return this._ConnStr;
            }
            set
            {
                this._ConnStr = value;
            }
        }

        private string _SchemaName;
        /// <summary></summary>
        public string SchemaName
        {
            get
            {
                return this._SchemaName;
            }
            set
            {
                this._SchemaName = value;
            }
        }

        private string _TableName;
        /// <summary></summary>
        public string TableName
        {
            get
            {
                return this._TableName;
            }
            set
            {
                this._TableName = value;
            }
        }

        private string _Sql;
        /// <summary></summary>
        public string Sql
        {
            get
            {
                return this._Sql;
            }
            set
            {
                this._Sql = value;
            }
        }

        private string _PKField;
        /// <summary></summary>
        public string PKField
        {
            get
            {
                return this._PKField;
            }
            set
            {
                this._PKField = value;
            }
        }

        private string _OrgNameField;
        /// <summary></summary>
        public string OrgNameField
        {
            get
            {
                return this._OrgNameField;
            }
            set
            {
                this._OrgNameField = value;
            }
        }

        private Dictionary<string,List<string>> _OrgEntityPatterns;
        /// <summary>
        /// org type->list of regex match patterns
        /// for example,
        /// university->(univ,coll,university,college,institute,inst)
        /// city->(US city names)
        /// state->(US state names)
        /// </summary>
        public Dictionary<string,List<string>> OrgEntityPatterns
        {
            get
            {
                return this._OrgEntityPatterns;
            }
            set
            {
                this._OrgEntityPatterns = value;
            }
        }

        private Dictionary<string,double> _OrgEntityWeights;
        /// <summary></summary>
        public Dictionary<string,double> OrgEntityWeights
        {
            get
            {
                return this._OrgEntityWeights;
            }
            set
            {
                this._OrgEntityWeights = value;
            }
        }

        private Dictionary<string,double> _OrgEntityPenalties;
        /// <summary></summary>
        public Dictionary<string,double> OrgEntityPenalties
        {
            get
            {
                return this._OrgEntityPenalties;
            }
            set
            {
                this._OrgEntityPenalties = value;
            }
        }

        private double _LinkThreshold;
        /// <summary></summary>
        public double LinkThreshold
        {
            get
            {
                return this._LinkThreshold;
            }
            set
            {
                this._LinkThreshold = value;
            }
        }

        private string _OutputTable;
        /// <summary></summary>
        public string OutputTable
        {
            get
            {
                return this._OutputTable;
            }
            set
            {
                this._OutputTable = value;
            }
        }
        #endregion

        #region ctor
        /// <summary>
        /// 
        /// </summary>
        public OrganizationEncodingInstruction():base(Guid.Empty,Guid.Empty)
        {
            this._ConnStr = string.Empty;
            this._SchemaName = string.Empty;
            this._TableName = string.Empty;
            this._Sql = string.Empty;
            this._PKField = string.Empty;
            this._OrgNameField = string.Empty;
            this._OrgEntityPatterns=new Dictionary<string, List<string>>();
            this._OrgEntityWeights=new Dictionary<string, double>();
            this._OrgEntityPenalties=new Dictionary<string, double>();
            this._LinkThreshold = 0.55;
            this._OutputTable = string.Empty;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="componentID"></param>
        /// <param name="jobTicketID"></param>
        /// <param name="connStr"></param>
        /// <param name="schema"></param>
        /// <param name="tblName"></param>
        /// <param name="sql"></param>
        /// <param name="pkField"></param>
        /// <param name="orgNameField"></param>
        /// <param name="patterns"></param>
        /// <param name="weights"></param>
        /// <param name="penalties"></param>
        /// <param name="threshold"></param>
        /// <param name="outputTable"></param>
        public OrganizationEncodingInstruction(Guid componentID, Guid jobTicketID,
            string connStr, string schema, string tblName, string sql,
            string pkField, string orgNameField, 
            Dictionary<string,List<string>> patterns, 
            Dictionary<string,double> weights, 
            Dictionary<string,double> penalties,
            double threshold, string outputTable) : base(componentID, jobTicketID)
        {
            this._ConnStr = connStr;
            this._SchemaName = schema;
            this._TableName = tblName;
            this._Sql = sql;
            this._PKField = pkField;
            this._OrgNameField = orgNameField;
            this._OrgEntityPatterns = patterns;
            this._OrgEntityWeights = weights;
            this._OrgEntityPenalties = penalties;
            this._LinkThreshold = threshold;
            this._OutputTable = outputTable;
        }
        #endregion

        #region Overrides of InstructionBase

        /// <summary>
        /// serialize settings to xml
        /// the function below is mainly for storing into database as serialized form instead of string
        /// </summary>
        public override XmlNode Serialize(ref XmlDocument xDoc, ref XmlNode parentNode)
        {
            XmlNode xNode = XmlDataUtil.AddElement(ref xDoc, parentNode, "Instruction");
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "Type", this.GetType().FullName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ComponentID", this.OwnerComponentID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "WorkerID", this.OwnerWorkerInstanceID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SubmitTime", this.SubmitTime.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "StartTime", this.StartTime.ToString());

            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ConnStr", this.ConnStr);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "Schema", this.SchemaName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TableName", this.TableName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "Sql", this.Sql);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "PKField", this.PKField);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "OrgNameField", this.OrgNameField);
            XmlNode entityNodes = XmlDataUtil.AddElement(ref xDoc, xNode, "Entities");
            if(this.OrgEntityPatterns !=null && this.OrgEntityPatterns.Count>0)
            {
                foreach(string entityName in this.OrgEntityPatterns.Keys)
                {
                    XmlNode entityNode = XmlDataUtil.AddElement(ref xDoc, entityNodes, "Entity");
                    XmlDataUtil.UpdateAttribute(ref xDoc, entityNode, "Name", entityName);
                    if(this.OrgEntityWeights!=null && this.OrgEntityWeights.ContainsKey(entityName))
                    {
                        XmlDataUtil.UpdateAttribute(ref xDoc, entityNode, "Weight", this.OrgEntityWeights[entityName].ToString());
                    }
                    if(this.OrgEntityPenalties !=null && this.OrgEntityPenalties.ContainsKey(entityName))
                    {
                        XmlDataUtil.UpdateAttribute(ref xDoc, entityNode, "Penalty", this.OrgEntityPenalties[entityName].ToString());
                    }
                    foreach (string pattern in this.OrgEntityPatterns[entityName])
                    {
                        XmlNode patternNode = XmlDataUtil.AddElement(ref xDoc, entityNode, "Pattern");
                        XmlDataUtil.UpdateAttribute(ref xDoc, patternNode, "Pattern", pattern);
                    }
                }
            }

            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "LinkThreshold", this.LinkThreshold.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "OutputTable", this.OutputTable);
            
            return xNode;
        }

        /// <summary>
        /// instantiated from xml
        /// "&lt;Instructions&gt;&lt;Instruction&gt;&lt;/Instruction&gt;&lt;/Instruction&gt;", must
        /// instantiate from first child of root node
        /// </summary>
        public override InstructionBase Instantiate(XmlNode xNode)
        {
            if (xNode.Attributes.GetNamedItem("Type").Value == this.GetType().FullName)
            {
                OrganizationEncodingInstruction instruction = new OrganizationEncodingInstruction();
                instruction.OwnerComponentID = new Guid(xNode.Attributes.GetNamedItem("ComponentID").Value);
                instruction.OwnerWorkerInstanceID = new Guid(xNode.Attributes.GetNamedItem("WorkerID").Value);
                instruction.SubmitTime = DateTime.Parse(xNode.Attributes.GetNamedItem("SubmitTime").Value);
                instruction.StartTime = DateTime.Parse(xNode.Attributes.GetNamedItem("StartTime").Value);

                instruction.ConnStr = XmlDataUtil.GetAttributeValue(xNode, "ConnStr", "");
                instruction.SchemaName = XmlDataUtil.GetAttributeValue(xNode, "Schema", "");
                instruction.TableName = XmlDataUtil.GetAttributeValue(xNode, "TableName", "");
                instruction.Sql = XmlDataUtil.GetAttributeValue(xNode, "Sql", "");
                instruction.PKField = XmlDataUtil.GetAttributeValue(xNode, "PKField", "");
                instruction.OrgNameField = XmlDataUtil.GetAttributeValue(xNode, "OrgNameField", "");
                instruction.OrgEntityPatterns=new Dictionary<string, List<string>>();
                instruction.OrgEntityWeights=new Dictionary<string, double>();
                instruction.OrgEntityPenalties=new Dictionary<string, double>();
                XmlNodeList entityNodes = xNode.SelectNodes("Entities/Entity");
                if(entityNodes !=null && entityNodes.Count>0)
                {
                    foreach(XmlNode entityNode in entityNodes)
                    {
                        string entityName = XmlDataUtil.GetAttributeValue(entityNode, "Name", "");
                        double weight = double.Parse(XmlDataUtil.GetAttributeValue(entityNode, "Weight", "0"));
                        double penalty = double.Parse(XmlDataUtil.GetAttributeValue(entityNode, "Penalty", "0"));
                        List<string> patterns=new List<string>();
                        instruction.OrgEntityWeights.Add(entityName, weight);
                        instruction.OrgEntityPenalties.Add(entityName, penalty);
                        if(entityNode.ChildNodes !=null && entityNode.ChildNodes.Count>0)
                        {
                            foreach(XmlNode patternNode in entityNode.ChildNodes)
                            {
                                string pattern = XmlDataUtil.GetAttributeValue(patternNode, "Pattern", "");
                                patterns.Add(pattern);
                            }
                        }
                        instruction.OrgEntityPatterns.Add(entityName, patterns);
                    }
                }

                instruction.LinkThreshold = double.Parse(XmlDataUtil.GetAttributeValue(xNode, "LinkThreshold", "0.55"));
                instruction.OutputTable = XmlDataUtil.GetAttributeValue(xNode, "OutputTable", "");

                return instruction;
            }
            else
            {
                throw new Exception("Unable to instantiate instruction: invalid type specified in xml node");
            }
        }

        #endregion
    }
}
